# _*_ coding: utf-8 _*_
# .@FileName:RevTrans
# .@Data....:2025-08-20 : 23 : 49
# .@Aurhor..:LiuJingYu
"""
launch:
from __future__ import unicode_literals, print_function
import maya.cmds as mc
"""
import maya.cmds as cmds
import maya.OpenMayaUI as omui
from PySide2 import QtCore, QtWidgets, QtGui
from shiboken2 import wrapInstance
import os
from datetime import datetime
import json
import re


class SkeletonDataHandler:
    """骨骼数据处理类，提供数据导出、加载和属性还原功能"""

    def __init__(self):
        self.custom_path = None
        self.loaded_data = None
        self.root_joint = None

        # 信号变量（用于Qt信号连接）
        self.status_updated = None  # 状态更新信号 (message, type)
        self.progress_updated = None  # 进度更新信号 (value)

    def set_custom_path(self, path):
        """设置自定义保存路径"""
        if not path:
            self._update_status("路径不能为空", "error")
            return False

        try:
            if not os.path.exists(path):
                os.makedirs(path)
                self._update_status(f"创建了新路径: {path}")

            self.custom_path = path
            self._update_status(f"自定义路径已设置: {path}")
            return True
        except Exception as e:
            self._update_status(f"设置路径失败: {str(e)}", "error")
            return False

    def set_root_joint(self, root_joint):
        """设置骨骼链根节点"""
        if not cmds.objExists(root_joint):
            self._update_status(f"骨骼 {root_joint} 不存在于场景中", "error")
            return False

        if cmds.objectType(root_joint) != 'joint':
            self._update_status(f"{root_joint} 不是一个骨骼对象", "error")
            return False

        self.root_joint = root_joint
        self._update_status(f"根骨骼已设置为: {root_joint}")
        return True

    def export_to_json(self):
        """导出骨骼数据到JSON文件"""
        if not self.root_joint:
            self._update_status("请先设置根骨骼", "error")
            return False

        try:
            # 获取骨骼数据
            skeleton_data = self._get_skeleton_transforms()
            if not skeleton_data:
                return False

            # 确定保存路径
            save_dir = self._get_save_directory()
            if not save_dir:
                return False

            # 获取JSON文件名和完整路径
            json_filename = self._get_json_filename()
            json_path = os.path.join(save_dir, json_filename)

            # 写入JSON文件
            with open(json_path, 'w', encoding='utf-8') as f:
                json.dump(skeleton_data, f, indent=4, ensure_ascii=False)

            self._update_status(
                f"成功导出 {skeleton_data['joint_count']} 个骨骼的数据到: {json_path}"
            )
            return True

        except Exception as e:
            self._update_status(f"导出失败: {str(e)}", "error")
            return False

    def load_from_json(self, json_filename=None):
        """从JSON文件加载骨骼数据"""
        if not self.custom_path or not os.path.exists(self.custom_path):
            self._update_status("请先设置并确认自定义路径存在", "error")
            return None

        try:
            # 确定文件名
            if not json_filename:
                json_filename = self._get_json_filename()

            # 构建完整路径
            json_path = os.path.join(self.custom_path, json_filename)

            # 检查文件是否存在
            if not os.path.exists(json_path):
                return self._handle_missing_file()

            # 加载JSON文件
            with open(json_path, 'r', encoding='utf-8') as f:
                self.loaded_data = json.load(f)

            # 显示加载的数据摘要，帮助调试
            joints_data = self.loaded_data.get("joints", {})
            sample_joints = list(joints_data.keys())[:3]  # 显示前3个骨骼作为样本
            self._update_status(
                f"成功从 {json_path} 加载数据，包含 {len(joints_data)} 个骨骼信息"
            )
            self._update_status(f"数据样本: {sample_joints}")

            return self.loaded_data

        except Exception as e:
            self._update_status(f"加载失败: {str(e)}", "error")
            return None

    def restore_all_attributes(self):
        """还原所有骨骼的位移和旋转属性"""
        if not self.loaded_data:
            self._update_status("请先加载JSON数据", "error")
            return False

        try:
            current_frame = cmds.currentTime(q=True)
            self._update_status(f"在帧 {current_frame} 还原所有骨骼属性...")

            joints_data = self.loaded_data.get("joints", {})
            total_joints = len(joints_data)
            restored_count = 0

            for i, (joint_name, attributes) in enumerate(joints_data.items()):
                # 更新进度
                self._update_progress(int((i / total_joints) * 100))

                # 检查骨骼是否存在
                if not self._is_valid_joint(joint_name):
                    continue

                # 还原位移属性
                translate = attributes.get("translate", {})
                self._set_attribute(joint_name, "translateX", translate.get("x", 0))
                self._set_attribute(joint_name, "translateY", translate.get("y", 0))
                self._set_attribute(joint_name, "translateZ", translate.get("z", 0))

                # 还原旋转属性
                rotate = attributes.get("rotate", {})
                self._set_attribute(joint_name, "rotateX", rotate.get("x", 0))
                self._set_attribute(joint_name, "rotateY", rotate.get("y", 0))
                self._set_attribute(joint_name, "rotateZ", rotate.get("z", 0))

                restored_count += 1

            self._update_progress(100)
            self._update_status(f"已成功还原 {restored_count} 个骨骼的所有属性")
            return True

        except Exception as e:
            self._update_status(f"还原属性失败: {str(e)}", "error")
            return False

    def restore_selected_rotate_x(self):
        """仅还原选中骨骼的旋转X轴属性"""
        return self._restore_selected_rotate_axis("X")

    def restore_selected_rotate_y(self):
        """仅还原选中骨骼的旋转Y轴属性"""
        return self._restore_selected_rotate_axis("Y")

    def restore_selected_rotate_z(self):
        """仅还原选中骨骼的旋转Z轴属性"""
        return self._restore_selected_rotate_axis("Z")

    def _restore_selected_rotate_axis(self, axis):
        """通用方法：还原选中骨骼的指定旋转轴属性"""
        if not self.loaded_data:
            self._update_status("请先加载JSON数据", "error")
            return False

        # 获取选中的骨骼
        selected_joints = cmds.ls(selection=True, type='joint', long=True)
        if not selected_joints:
            self._update_status(f"请先选择一个或多个骨骼以还原旋转{axis}轴", "warning")
            return False

        self._update_status(f"检测到选中的骨骼: {selected_joints}")

        try:
            current_frame = cmds.currentTime(q=True)
            self._update_status(f"在帧 {current_frame} 还原选中骨骼的旋转{axis}轴属性...")

            joints_data = self.loaded_data.get("joints", {})
            total_joints = len(selected_joints)
            restored_count = 0

            axis_lower = axis.lower()  # 转为小写用于访问数据
            attr_name = f"rotate{axis}"  # 属性名称如rotateX

            for i, joint_name in enumerate(selected_joints):
                # 更新进度
                self._update_progress(int((i / total_joints) * 100))

                # 尝试短名称匹配（如果长名称不匹配）
                short_name = joint_name.split('|')[-1]
                joint_key = self._find_matching_joint_key(joint_name, short_name, joints_data)

                # 检查骨骼是否存在于数据中
                if not joint_key:
                    self._update_status(
                        f"警告: 骨骼 {joint_name} (短名称: {short_name}) 不在保存的数据中，已跳过",
                        "warning"
                    )
                    continue

                # 检查骨骼是否有效
                if not self._is_valid_joint(joint_name):
                    continue

                # 获取旋转轴数据
                rotate = joints_data[joint_key].get("rotate", {})
                rotate_value = rotate.get(axis_lower, None)

                if rotate_value is None:
                    self._update_status(f"警告: 骨骼 {joint_name} 没有旋转{axis}轴数据", "warning")
                    continue

                # 设置旋转轴属性
                try:
                    # 先获取当前值
                    current_value = cmds.getAttr(f"{joint_name}.{attr_name}")
                    # 设置新值
                    cmds.setAttr(f"{joint_name}.{attr_name}", rotate_value)
                    # 验证是否设置成功
                    new_value = cmds.getAttr(f"{joint_name}.{attr_name}")

                    if abs(new_value - rotate_value) < 0.001:  # 允许微小浮点误差
                        self._update_status(
                            f"已将 {joint_name} 的{attr_name}从 {current_value:.2f} 设为 {rotate_value:.2f}",
                            "info"
                        )
                        restored_count += 1
                    else:
                        self._update_status(
                            f"警告: {joint_name} 的{attr_name}设置失败，当前值: {new_value:.2f}",
                            "warning"
                        )
                except Exception as e:
                    self._update_status(
                        f"无法设置 {joint_name}.{attr_name}: {str(e)}",
                        "warning"
                    )

            self._update_progress(100)
            self._update_status(f"已成功还原 {restored_count}/{total_joints} 个选中骨骼的旋转{axis}轴属性")
            return True

        except Exception as e:
            self._update_status(f"还原旋转{axis}轴失败: {str(e)}", "error")
            return False

    def restore_selected_all_attributes(self):
        """还原选中骨骼的所有原始属性（位移和旋转）"""
        if not self.loaded_data:
            self._update_status("请先加载JSON数据", "error")
            return False

        # 获取选中的骨骼
        selected_joints = cmds.ls(selection=True, type='joint', long=True)
        if not selected_joints:
            self._update_status("请先选择一个或多个骨骼以还原所有属性", "warning")
            return False

        self._update_status(f"检测到选中的骨骼: {selected_joints}")

        try:
            current_frame = cmds.currentTime(q=True)
            self._update_status(f"在帧 {current_frame} 还原选中骨骼的所有属性...")

            joints_data = self.loaded_data.get("joints", {})
            total_joints = len(selected_joints)
            restored_count = 0

            for i, joint_name in enumerate(selected_joints):
                # 更新进度
                self._update_progress(int((i / total_joints) * 100))

                # 尝试短名称匹配（如果长名称不匹配）
                short_name = joint_name.split('|')[-1]
                joint_key = self._find_matching_joint_key(joint_name, short_name, joints_data)

                # 检查骨骼是否存在于数据中
                if not joint_key:
                    self._update_status(
                        f"警告: 骨骼 {joint_name} (短名称: {short_name}) 不在保存的数据中，已跳过",
                        "warning"
                    )
                    continue

                # 检查骨骼是否有效
                if not self._is_valid_joint(joint_name):
                    continue

                # 获取所有属性数据
                attributes = joints_data[joint_key]
                translate = attributes.get("translate", {})
                rotate = attributes.get("rotate", {})

                # 还原位移属性
                self._set_attribute(joint_name, "translateX", translate.get("x", 0))
                self._set_attribute(joint_name, "translateY", translate.get("y", 0))
                self._set_attribute(joint_name, "translateZ", translate.get("z", 0))

                # 还原旋转属性
                self._set_attribute(joint_name, "rotateX", rotate.get("x", 0))
                self._set_attribute(joint_name, "rotateY", rotate.get("y", 0))
                self._set_attribute(joint_name, "rotateZ", rotate.get("z", 0))

                restored_count += 1
                self._update_status(f"已还原 {joint_name} 的所有属性", "info")

            self._update_progress(100)
            self._update_status(f"已成功还原 {restored_count}/{total_joints} 个选中骨骼的所有属性")
            return True

        except Exception as e:
            self._update_status(f"还原选中骨骼属性失败: {str(e)}", "error")
            return False

    def check_json_exists(self, json_filename=None):
        """检查JSON文件是否存在"""
        if not self.custom_path or not os.path.exists(self.custom_path):
            self._update_status("请先设置并确认自定义路径存在", "error")
            return False

        try:
            # 确定文件名
            if not json_filename:
                json_filename = self._get_json_filename()

            # 构建完整路径
            json_path = os.path.join(self.custom_path, json_filename)

            # 检查文件是否存在
            if os.path.exists(json_path):
                self._update_status(f"JSON文件存在: {json_path}")
                return True
            else:
                self._update_status(f"JSON文件不存在: {json_path}", "warning")
                return False

        except Exception as e:
            self._update_status(f"检查文件失败: {str(e)}", "error")
            return False

    def get_available_json_files(self):
        """获取自定义路径下所有可用的JSON文件"""
        if not self.custom_path or not os.path.exists(self.custom_path):
            return []

        return [f for f in os.listdir(self.custom_path) if f.endswith('.json')]

    # 内部辅助方法
    def _find_matching_joint_key(self, long_name, short_name, joints_data):
        """查找匹配的骨骼键，尝试多种匹配方式"""
        # 先尝试长名称匹配
        if long_name in joints_data:
            return long_name
        # 再尝试短名称匹配
        elif short_name in joints_data:
            return short_name
        # 最后尝试部分匹配
        else:
            for key in joints_data:
                if short_name in key or key in short_name:
                    return key
        return None

    def _get_skeleton_transforms(self):
        """获取骨骼变换数据 - 同时保存长名称和短名称以提高兼容性"""
        skeleton_chain = self._get_all_joints()

        return {
            "export_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "root_joint": self.root_joint,
            "root_joint_long": cmds.ls(self.root_joint, long=True)[0],  # 保存长名称
            "joint_count": len(skeleton_chain),
            "maya_file": cmds.file(q=True, sceneName=True),
            "joints": self._collect_joint_attributes(skeleton_chain)
        }

    def _get_all_joints(self):
        """递归获取所有骨骼"""
        if not self.root_joint:
            return []

        joints = [self.root_joint]
        children = cmds.listRelatives(self.root_joint, type='joint', children=True)

        if children:
            for child in children:
                joints.extend(self._get_all_joints_recursive(child))

        return joints

    def _get_all_joints_recursive(self, joint):
        """递归获取子骨骼"""
        joints = [joint]
        children = cmds.listRelatives(joint, type='joint', children=True)

        if children:
            for child in children:
                joints.extend(self._get_all_joints_recursive(child))

        return joints

    def _collect_joint_attributes(self, joints):
        """收集骨骼属性 - 使用长名称作为键，同时保存短名称"""
        joint_data = {}

        for joint in joints:
            # 获取长名称作为主键
            long_name = cmds.ls(joint, long=True)[0]
            short_name = joint.split('|')[-1]

            translate = cmds.getAttr(f"{joint}.translate")
            rotate = cmds.getAttr(f"{joint}.rotate")

            joint_data[long_name] = {
                "short_name": short_name,  # 保存短名称用于匹配
                "translate": {
                    "x": translate[0][0],
                    "y": translate[0][1],
                    "z": translate[0][2]
                },
                "rotate": {
                    "x": rotate[0][0],
                    "y": rotate[0][1],
                    "z": rotate[0][2]
                }
            }

        return joint_data

    def _get_json_filename(self):
        """生成JSON文件名"""
        maya_file = cmds.file(q=True, sceneName=True)
        if not maya_file:
            raise ValueError("请先保存当前Maya场景")

        base_name = os.path.basename(maya_file)
        name_without_ext = os.path.splitext(base_name)[0]

        # 替换命名模式
        new_name = re.sub(r'_PD_Anim$', '_dataJson', name_without_ext)
        if new_name == name_without_ext:
            new_name = f"{name_without_ext}_dataJson"

        return f"{new_name}.json"

    def _get_save_directory(self):
        """获取保存目录"""
        if self.custom_path and os.path.exists(self.custom_path):
            return self.custom_path

        # 使用Maya文件目录
        maya_file = cmds.file(q=True, sceneName=True)
        save_dir = os.path.dirname(maya_file)

        if not save_dir:  # 场景未保存时使用工作目录
            save_dir = cmds.workspace(q=True, rd=True)
            self._update_status(f"场景未保存，使用默认工作目录: {save_dir}", "warning")

        return save_dir

    def _is_valid_joint(self, joint_name):
        """检查是否为有效的骨骼"""
        if not cmds.objExists(joint_name):
            self._update_status(f"警告: 骨骼 {joint_name} 不存在，已跳过", "warning")
            return False

        if cmds.objectType(joint_name) != 'joint':
            self._update_status(f"警告: {joint_name} 不是骨骼对象，已跳过", "warning")
            return False

        return True

    def _set_attribute(self, joint, attr, value):
        """设置骨骼属性值"""
        try:
            cmds.setAttr(f"{joint}.{attr}", value)
        except Exception as e:
            self._update_status(f"无法设置 {joint}.{attr}: {str(e)}", "warning")

    def _handle_missing_file(self):
        """处理文件不存在的情况"""
        json_files = self.get_available_json_files()
        if not json_files:
            raise FileNotFoundError(f"在 {self.custom_path} 中未找到任何JSON文件")

        self._update_status(f"在 {self.custom_path} 中找到以下JSON文件:")
        for i, f in enumerate(json_files):
            self._update_status(f"{i + 1}. {f}")
        return None

    def _update_status(self, message, message_type="info"):
        """更新状态信息（安全处理信号调用）"""
        print(f"[{message_type.upper()}] {message}")
        # 安全检查信号是否存在且可调用
        if hasattr(self.status_updated, 'emit'):
            self.status_updated.emit(message, message_type)
        elif self.status_updated is not None:
            # 如果是直接绑定的函数，则直接调用
            try:
                self.status_updated(message, message_type)
            except Exception:
                pass

    def _update_progress(self, value):
        """更新进度（安全处理信号调用）"""
        # 安全检查信号是否存在且可调用
        if hasattr(self.progress_updated, 'emit'):
            self.progress_updated.emit(value)
        elif self.progress_updated is not None:
            # 如果是直接绑定的函数，则直接调用
            try:
                self.progress_updated(value)
            except Exception:
                pass


class SkeletonToolUI(QtWidgets.QDialog):
    """骨骼数据处理工具界面 - 增强版"""

    # 定义Qt信号
    status_updated = QtCore.Signal(str, str)
    progress_updated = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(SkeletonToolUI, self).__init__(parent)

        # 设置窗口标志
        self.setWindowFlags(
            QtCore.Qt.Window |
            QtCore.Qt.WindowTitleHint |
            QtCore.Qt.WindowCloseButtonHint |
            QtCore.Qt.WindowMinimizeButtonHint
        )

        # 设置窗口标题和大小
        self.setWindowTitle("骨骼数据处理工具 2.0")
        self.resize(700, 500)
        self.setMinimumSize(600, 400)

        # 创建数据处理器实例
        self.handler = SkeletonDataHandler()

        # 正确连接信号 - 将UI的信号与处理器的回调关联
        self.status_updated.connect(self.update_status)
        self.progress_updated.connect(self.update_progress)

        # 将处理器的信号指向UI的信号
        self.handler.status_updated = self.status_updated
        self.handler.progress_updated = self.progress_updated

        # 初始化UI
        self.init_ui()

    def init_ui(self):
        """初始化界面元素"""
        # 创建主布局
        main_layout = QtWidgets.QVBoxLayout(self)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(8)

        # 1. 路径设置区域
        path_group = QtWidgets.QGroupBox("文件路径设置")
        path_layout = QtWidgets.QHBoxLayout()

        self.path_edit = QtWidgets.QLineEdit()
        self.path_edit.setPlaceholderText("输入或选择文件路径...")

        self.browse_btn = QtWidgets.QPushButton("浏览...")
        self.browse_btn.clicked.connect(self.browse_path)

        path_layout.addWidget(self.path_edit)
        path_layout.addWidget(self.browse_btn)
        path_group.setLayout(path_layout)
        main_layout.addWidget(path_group)

        # 2. 根骨骼选择区域
        root_group = QtWidgets.QGroupBox("根骨骼设置")
        root_layout = QtWidgets.QHBoxLayout()

        self.root_joint_combo = QtWidgets.QComboBox()
        self.refresh_joints_btn = QtWidgets.QPushButton("刷新骨骼列表")
        self.refresh_joints_btn.clicked.connect(self.refresh_joint_list)

        root_layout.addWidget(self.root_joint_combo)
        root_layout.addWidget(self.refresh_joints_btn)
        root_group.setLayout(root_layout)
        main_layout.addWidget(root_group)

        # 3. 操作按钮区域
        button_layout = QtWidgets.QGridLayout()

        # 第一行按钮：数据管理
        self.export_btn = QtWidgets.QPushButton("导出骨骼数据")
        self.export_btn.clicked.connect(self.export_data)

        self.load_btn = QtWidgets.QPushButton("加载JSON数据")
        self.load_btn.clicked.connect(self.load_data)

        self.check_file_btn = QtWidgets.QPushButton("检查JSON是否存在")
        self.check_file_btn.clicked.connect(self.check_file_exists)

        # 第二行按钮：全部还原
        self.restore_all_btn = QtWidgets.QPushButton("还原所有骨骼的所有属性")
        self.restore_all_btn.clicked.connect(self.restore_all_attributes)

        # 第三行按钮：选中骨骼还原所有属性
        self.restore_selected_all_btn = QtWidgets.QPushButton("还原选中骨骼的所有属性")
        self.restore_selected_all_btn.clicked.connect(self.restore_selected_all_attributes)

        # 第四行按钮：单独旋转轴还原
        self.restore_rx_btn = QtWidgets.QPushButton("还原选中骨骼的旋转X轴")
        self.restore_rx_btn.clicked.connect(self.restore_selected_rotate_x)

        self.restore_ry_btn = QtWidgets.QPushButton("还原选中骨骼的旋转Y轴")
        self.restore_ry_btn.clicked.connect(self.restore_selected_rotate_y)

        self.restore_rz_btn = QtWidgets.QPushButton("还原选中骨骼的旋转Z轴")
        self.restore_rz_btn.clicked.connect(self.restore_selected_rotate_z)

        # 添加到布局
        button_layout.addWidget(self.export_btn, 0, 0)
        button_layout.addWidget(self.load_btn, 0, 1)
        button_layout.addWidget(self.check_file_btn, 0, 2)
        button_layout.addWidget(self.restore_all_btn, 1, 0, 1, 3)  # 跨三列
        button_layout.addWidget(self.restore_selected_all_btn, 2, 0, 1, 3)  # 跨三列
        button_layout.addWidget(self.restore_rx_btn, 3, 0)
        button_layout.addWidget(self.restore_ry_btn, 3, 1)
        button_layout.addWidget(self.restore_rz_btn, 3, 2)

        main_layout.addLayout(button_layout)

        # 4. 进度条
        self.progress_bar = QtWidgets.QProgressBar()
        self.progress_bar.setVisible(False)
        main_layout.addWidget(self.progress_bar)

        # 5. 状态信息区域
        status_group = QtWidgets.QGroupBox("状态信息")
        status_layout = QtWidgets.QVBoxLayout()

        self.status_text = QtWidgets.QTextEdit()
        self.status_text.setReadOnly(True)
        status_layout.addWidget(self.status_text)

        status_group.setLayout(status_layout)
        main_layout.addWidget(status_group)

        # 初始刷新骨骼列表
        self.refresh_joint_list()

    def browse_path(self):
        """浏览并选择路径"""
        default_path = self.path_edit.text() or os.path.expanduser("~")
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self, "选择保存目录", default_path
        )

        if path:
            self.path_edit.setText(path)
            self.handler.set_custom_path(path)

    def refresh_joint_list(self):
        """刷新骨骼列表"""
        self.root_joint_combo.clear()

        # 获取场景中所有骨骼
        all_joints = cmds.ls(type='joint')
        if all_joints:
            self.root_joint_combo.addItems(all_joints)
            # 尝试自动选择名为root或Root的骨骼
            for i, joint in enumerate(all_joints):
                if joint.lower() == "root":
                    self.root_joint_combo.setCurrentIndex(i)
                    break

            # 设置根骨骼
            self.handler.set_root_joint(self.root_joint_combo.currentText())
        else:
            self.update_status("场景中没有找到骨骼", "warning")

    def export_data(self):
        """导出骨骼数据"""
        # 确保路径已设置
        path = self.path_edit.text()
        if path:
            self.handler.set_custom_path(path)

        # 确保根骨骼已设置
        root_joint = self.root_joint_combo.currentText()
        if root_joint:
            self.handler.set_root_joint(root_joint)

        # 执行导出
        self.handler.export_to_json()

    def load_data(self):
        """加载JSON数据"""
        # 确保路径已设置
        path = self.path_edit.text()
        if path:
            self.handler.set_custom_path(path)

        # 执行加载
        self.handler.load_from_json()

    def check_file_exists(self):
        """检查JSON文件是否存在"""
        # 确保路径已设置
        path = self.path_edit.text()
        if path:
            self.handler.set_custom_path(path)

        # 执行检查
        self.handler.check_json_exists()

    def restore_all_attributes(self):
        """还原所有骨骼的所有属性"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.handler.restore_all_attributes()

    def restore_selected_all_attributes(self):
        """还原选中骨骼的所有属性"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.handler.restore_selected_all_attributes()

    def restore_selected_rotate_x(self):
        """还原选中骨骼的旋转X轴"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.handler.restore_selected_rotate_x()

    def restore_selected_rotate_y(self):
        """还原选中骨骼的旋转Y轴"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.handler.restore_selected_rotate_y()

    def restore_selected_rotate_z(self):
        """还原选中骨骼的旋转Z轴"""
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.handler.restore_selected_rotate_z()

    def update_status(self, message, message_type="info"):
        """更新状态信息显示 - 默认颜色为绿色"""
        # 根据消息类型设置颜色
        color = "green"  # 默认颜色为绿色
        if message_type == "error":
            color = "red"
        elif message_type == "warning":
            color = "orange"

        # 添加时间戳
        timestamp = datetime.now().strftime("%H:%M:%S")

        # 追加到文本区域
        self.status_text.append(
            f'<span style="color:{color}">[{timestamp}] {message}</span>'
        )

        # 滚动到底部
        self.status_text.verticalScrollBar().setValue(
            self.status_text.verticalScrollBar().maximum()
        )

    def update_progress(self, value):
        """更新进度条"""
        self.progress_bar.setValue(value)


def get_maya_main_window():
    """获取Maya主窗口作为父窗口"""
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)


def show_tool():
    """显示工具窗口"""
    # 关闭已存在的窗口实例
    for widget in QtWidgets.QApplication.allWidgets():
        if isinstance(widget, SkeletonToolUI):
            widget.close()

    # 创建并显示新窗口
    main_window = get_maya_main_window()
    tool_ui = SkeletonToolUI(parent=main_window)
    tool_ui.show()


# 运行工具
if __name__ == "__main__":
    show_tool()




